<template>
  <div>
    <el-form ref="form" label-width="80px">
      <el-form-item label="SPU名称">
        <el-input placeholder="SPU名称" v-model="spu.spuName"></el-input>
      </el-form-item>
      <el-form-item label="品牌">
        <el-select placeholder="请选择品牌" v-model="spu.tmId">
          <el-option
            v-for="item in  tradeMarkList"
            :key="item.id"
            :label="item.tmName"
            :value="item.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="SPU描述">
        <el-input type="textarea" rows="4" placeholder="SPU描述" v-model="spu.description"></el-input>
      </el-form-item>
      <el-form-item label="SPU图片">
        <!-- action:图片上传地址
        on-preview	点击文件列表中已上传的文件时的钩子
        on-remove	文件列表移除文件时的钩子
         :file-list="SpuImageList" 展示照片墙列表
        -->
        <el-upload
          action="dev-api/admin/product/fileUpload"
          list-type="picture-card"
          :on-preview="handlePictureCardPreview"
          :on-remove="handleRemove"
          :file-list="spuImageList"
          :on-success="handlerSucess"
        >
          <i class="el-icon-plus"></i>
        </el-upload>
        <el-dialog :visible.sync="dialogVisible">
          <img width="100%" :src="dialogImageUrl" alt />
        </el-dialog>
      </el-form-item>

      <el-form-item label="销售属性">
        <el-select :placeholder="`还有${unSelectSaleAttr.length}未选择`" v-model="attrIdAndName">
          <el-option
            v-for="unSelect in unSelectSaleAttr "
            :key="unSelect.id"
            :label="unSelect.name"
            :value="`${unSelect.id}:${unSelect.name}`"
          ></el-option>
        </el-select>
        <el-button
          type="primary"
          icon="el-icon-plus"
          :disabled="!attrIdAndName"
          @click="addAttr"
        >添加销售属性</el-button>
        <el-table border style="width: 100%" :data="spu.spuSaleAttrList">
          <el-table-column type="index" label="序号" width="80px" align="center"></el-table-column>
          <el-table-column prop="saleAttrName" label="属性名" width="width"></el-table-column>
          <el-table-column prop label="属性值名称列表" width="width">
            <template slot-scope="{row,$index}">
              <!--  @close="row.spuSaleAttrValueList.splice(index,1)" 
               close点击叉号触发
              删除对应索引的销售属性值
              -->
              <el-tag
                :key="tag.id"
                v-for="(tag,index) in row.spuSaleAttrValueList"
                closable
                :disable-transitions="false"
                @close="row.spuSaleAttrValueList.splice(index,1)"
              >{{tag.saleAttrValueName}}</el-tag>
              <!-- v-if="inputVisible" 控制切换 查看与编辑模式 -->
              <el-input
                class="input-new-tag"
                v-if="row.inputVisible"
                v-model="row.inputValue"
                ref="saveTagInput"
                size="small"
                @blur="handleInputConfirm(row)"
              ></el-input>
              <el-button v-else class="button-new-tag" size="small" @click="addAttrValue(row)">添加</el-button>
            </template>
          </el-table-column>
          <el-table-column prop="prop" label="操作" width="width">
            <template slot-scope="{row,$index}">
              <!-- 
                 @click="spu.spuSaleAttrList.splice($index,1)
                 根据销售属性索引删除当前的销售属性 
              -->
              <el-button
                type="danger"
                icon="el-icon-delete"
                @click="spu.spuSaleAttrList.splice($index,1)"
              ></el-button>
            </template>
          </el-table-column>
        </el-table>

        <el-button type="primary" @click="addOrUpdateSpu">保存</el-button>
        <el-button @click="cancel">取消</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  name: "MySpuFrom",
  data() {
    return {
      dialogImageUrl: "",
      dialogVisible: false,
      // spu属性初始化时为空对象 在修改spu的时候 会向服务器发请求 返回spu信息对象 在修改的时候可以利用服务器返回的这个对象收集最新的数据提交给服务器
      // 但添加spu 并没有向服务器发送请求 数据收集到哪里啊?[spu,手动配置] 要收集那些字段见文档
      // 储存获取到的spu信息
      spu: {
        category3Id: 0,
        // 描述
        description: "",
        // spu名称
        spuNmae: "",
        // 品牌id(拿到id即可)
        tmId: "",
        // 收集spu图片的信息
        spuImageList: [
          {
            // id: 0,
            // imgName: "",
            // imgUrl: "",
            // spuId: 0
          }
        ],
        // 平台属性与属性值收集
        spuSaleAttrList: [
          {
            // baseSaleAttrId: 0,
            // id: 0,
            // saleAttrName: "",
            // spuId: 0,
            spuSaleAttrValueList: [
              {
                // baseSaleAttrId: 0,
                // id: 0,
                // isChecked: "",
                // saleAttrName: "",
                // saleAttrValueName: "",
                // spuId: 0
              }
            ]
          }
        ]
      },
      // 储存获取到的  tradeMarkResult信息
      tradeMarkList: [],
      // 储存获取到的 SpuImageList图片信息
      spuImageList: [],
      // 储存获取到的 baseSakeAttrList销售属性信息
      baseSaleAttrList: [],
      // 收集未选择的属性id和名字
      attrIdAndName: []
    };
  },
  methods: {
    // 对于已有的图片 照片墙中显示的图片:有name url 字段.因为照片墙显示数据（图片列表）务必要有这两个属性
    // 但是对于服务器而言是不需要这俩字段了 所以后续 进行保存提交服务器时需要额外处理（移除）
    // file代表删除的那种图片 fileList照片墙删除某一张图片后剩余的图片
    // 不管是新增还是删除都需要整理好照片墙数据 以便后续保存提交至服务器
    // 当照片墙删除某一张图片时会触发
    handleRemove(file, fileList) {
      this.spuImageList = fileList;
    },
    // 图片上传成功后（新增）触发的回调
    handlerSucess(response, file, fileList) {
      this.spuImageList = fileList;
    },
    //这是放大图片（预览） 无需收集照片参数
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    // 初始化spuFrom的数据
    // 为什么不直接在mounted中请求呢？
    // 因该子组件只会挂载一次即mounted只会执行一次 但 请求 却需要发送多次所以mounted不可用
    async initSpuData(spu) {
      // 获取spu信息
      let spuResult = await this.$API.spu.reqSpu(spu.id);
      if (spuResult.code == 200) {
        console.log(spuResult);
        this.spu = spuResult.data;
      }
      // 获取品牌信息
      let tradeMarkResult = await this.$API.spu.reqTradMarkList();
      if (tradeMarkResult.code == 200) {
        console.log(tradeMarkResult);
        this.tradeMarkList = tradeMarkResult.data;
      }
      //  获取图标
      let SpuImageListResult = await this.$API.spu.reqSpuImageList(spu.id);
      if (SpuImageListResult.code == 200) {
        console.log(SpuImageListResult);
        let imageList = SpuImageListResult.data;
        // 因展示图片列表需要用file-list字段 而它依赖name/url属性 所以拿到数据第一时间先添加上 以便使用
        imageList.forEach(item => {
          item.name = item.imgName;
          item.url = item.imgUrl;
        });
        // 数组在用数组方法增删元素 vue是可以监测到的也就是依旧是响应式
        this.spuImageList = imageList;
      }
      // 获取平台全部销售属性
      let baseSaleAttrListResult = await this.$API.spu.reqBaseSaleAttrList();
      if (baseSaleAttrListResult.code == 200) {
        console.log(baseSaleAttrListResult);
        this.baseSaleAttrList = baseSaleAttrListResult.data;
      }
    },
    // 添加销售属性业务
    addAttr() {
      // 收集服务器需要的字段
      const [baseSaleAttrId, saleAttrName] = this.attrIdAndName.split(":");
      // 整理成对象格式
      let newSaleAttr = {
        baseSaleAttrId,
        saleAttrName,
        spuSaleAttrValueList: []
      };
      // 列表展示添加后所有销售属性（后期在点击保存在进行提交至服务器）
      this.spu.spuSaleAttrList.push(newSaleAttr);
      // 添加销售属性完成后将select框清空
      this.attrIdAndName = "";
    },
    // 点击添加销售属性值业务
    addAttrValue(row) {
      // 添加用于控制切换编辑模式的字段 （el-ui封装好的）注意需要使用set添加不然不是响应式数据
      this.$set(row, "inputVisible", true);
      this.$set(row, "inputValue", "");
    },
    // 添加销售属性值后失去焦点校验值的合法性后整理数据展示
    handleInputConfirm(row) {
      const { baseSaleAttrId, inputValue } = row;
      //  销售属性值不能为空
      if (inputValue.trim() === "") {
        this.$message("属性值不能为空");
        return;
      }
      // 销售属性值不能重复添加
      // 如果属性值与新增属性值一致 则 return （some返回符合筛选条件的布尔值）
      let result = row.spuSaleAttrValueList.some(
        item => item.saleAttrValueName == inputValue
      );
      if (result) {
        this.$message("不能重复添加");
        return;
      }
      // 整理销售属性所需字段
      let newAttrValue = { baseSaleAttrId, saleAttrValueName: inputValue };
      // 添加至响应式数据用于展示
      row.spuSaleAttrValueList.push(newAttrValue);
      // 切换显示模式
      row.inputVisible = false;
    },
    //  保存业务 (修改spu)
    async addOrUpdateSpu() {
      // 整理用户上传的图片数据字段发送至服务器
      this.spu.spuImageList = this.spuImageList.map(item => {
        return {
          imgName: item.name,
          imgUrl: (item.response && item.response.data) || item.url
        };
      });
      let result = await this.$API.spu.reqAddOrUpDateSpu(this.spu);
      if (result.code === 200) {
        this.$message({
          type: "success",
          message: this.spu.id ? "修改成功" : "添加成功"
        });
        // 通知父组件用户操作的是新增还是修改【spu】以便父展示相应的spu页码
        this.$emit("changeScenc", {
          scene: 0,
          flag: this.spu.id ? "修改" : "添加"
        });
      }
      // 清空保存按钮操作的上次残留数据 有假报错 目前无法解决
      // Object.assign：es6新增合并对象方法
      // this._data：vm存储响应式数据的对象
      // this.$options.data()：当前data函数中配置的初始默认属性
      // 原理：Object.assign第二个参数数据会合并覆盖第一个参数数据 即响应式数据被初始数据覆盖为空 达成清空的效果
      Object.assign(this._data, this.$options.data());
    },
    // 父组件那边点击添加spu时 子组件发请求拉取品牌列表和销售属性
    async getSpuDate(category3Id) {
      // 点击添加spu并没有向服务器发送请求进行初始化数据 所以没有接收到category3Id
      // 但category3Id是请求必须携带的参数所以需要手动拿到进行存储
      this.spu.category3Id = category3Id;
      // 获取品牌信息
      let tradeMarkResult = await this.$API.spu.reqTradMarkList();
      if (tradeMarkResult.code == 200) {
        this.tradeMarkList = tradeMarkResult.data;
      }
      // 获取平台全部销售属性
      let baseSaleAttrListResult = await this.$API.spu.reqBaseSaleAttrList();
      if (baseSaleAttrListResult.code == 200) {
        this.baseSaleAttrList = baseSaleAttrListResult.data;
      }
    },
    cancel() {
      this.$emit("changeScenc", { scene: 0, flag: "" });
      // 清空取消按钮操作的上次残留数据 有假报错 目前无法解决
      Object.assign(this._data, this.$options.data());
    }
  },
  // 计算未选择的销售属性个数
  computed: {
    unSelectSaleAttr() {
      let result = this.baseSaleAttrList.filter(item => {
        return this.spu.spuSaleAttrList.every(item1 => {
          return item.name != item1.saleAttrName;
        });
      });
      return result;
    }
  }
};
</script>

<style>
.el-tag + .el-tag {
  margin-left: 10px;
}
.button-new-tag {
  margin-left: 10px;
  height: 32px;
  line-height: 30px;
  padding-top: 0;
  padding-bottom: 0;
}
.input-new-tag {
  width: 90px;
  margin-left: 10px;
  vertical-align: bottom;
}
</style>